#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//条件变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//锁

// void *threadRoutine(void *args)
// {
//     std::string name = static_cast<const char*>(args);

//     while(true)
//     {
//         sleep(1);
//         pthread_mutex_lock(&mutex);
//         pthread_cond_wait(&cond, &mutex);//注意加不加这句代码的区别
//         std::cout << "I am new thread : " << name << std::endl;
//         pthread_mutex_unlock(&mutex);
//     }
// }

int tickets = 100;
void *threadRoutine(void *args)
{
    std::string name = static_cast<const char*>(args);

    while(true)
    {
        sleep(1);
        pthread_mutex_lock(&mutex);
        if(tickets > 0)
        {
            std::cout << name << ", get a ticket: " <<  tickets-- << std::endl; // 模拟抢票
            usleep(10);
        }
        else
        {
            std::cout << "没有票了，" << name << std::endl;//
            pthread_cond_wait(&cond, &mutex);//注意加不加这句代码的区别,不加就是在每个线程大量的申请锁，释放锁
            //1.让线程在等待的时候，会自动释放锁
            //2.线程被唤醒的时候，是在临界区内被唤醒的，当线程被唤醒，线程在pthread_cond_wait返回的时候，要重新申请并持有锁
            //3.当线程被唤醒的时候，重新申请锁并持有锁本质要参与锁的竞争
            
        }       
        
        pthread_mutex_unlock(&mutex);
    }
}

//主线程
int main()
{
    pthread_t t1, t2, t3;
    pthread_create(&t1, nullptr, threadRoutine, (void*)"thread-1");
    pthread_create(&t2, nullptr, threadRoutine, (void*)"thread-2");
    pthread_create(&t3, nullptr, threadRoutine, (void*)"thread-3");

    // sleep(5); //for test, 5s开始进行让cond成立，唤醒一个线程
    // while(true)
    // {
    //     pthread_cond_signal(&cond);
    //     pthread_cond_broadcast(&cond);//唤醒在该条件变量下的所有线程
    //     sleep(1);
    // }
    sleep(5);

    while(true)
    {
        sleep(10);
        pthread_mutex_lock(&mutex);
        tickets += 100;
        pthread_mutex_unlock(&mutex);
        pthread_cond_broadcast(&cond);//同时唤醒上面三个抢票进程
        pthread_cond_signal(&cond);//依次唤醒单个线程
    }
    
    

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);

    

    return 0;
}

